今天是第八天我們可以寫一個k8s圖書館資料庫管理系統,以下是我的程式碼
首先需要建立一個 MySQL 部署在 Kubernetes 上的環境。
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: rootpassword
- name: MYSQL_DATABASE
value: library
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
後端可以使用 Node.js,通過 Express 框架建立一個 REST API,並與 MySQL 進行交互。
package.json
{
"name": "library-api",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"express": "^4.17.1",
"mysql2": "^2.1.0"
}
}
app.js
const express = require('express');
const mysql = require('mysql2');
const app = express();
app.use(express.json());
const connection = mysql.createConnection({
host: 'mysql',
user: 'root',
password: 'rootpassword',
database: 'library'
});
app.get('/books', (req, res) => {
connection.query('SELECT * FROM books', (err, results) => {
if (err) throw err;
res.json(results);
});
});
app.post('/books', (req, res) => {
const { title, author } = req.body;
connection.query('INSERT INTO books (title, author) VALUES (?, ?)', [title, author], (err) => {
if (err) throw err;
res.send('Book added!');
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Library API running on port ${PORT}`);
});
apiVersion: apps/v1
kind: Deployment
metadata:
name: library-backend
spec:
replicas: 1
selector:
matchLabels:
app: library-backend
template:
metadata:
labels:
app: library-backend
spec:
containers:
- name: library-backend
image: node:14
command: ["npm", "start"]
workingDir: /app
ports:
- containerPort: 3000
volumeMounts:
- name: app-source
mountPath: /app
volumes:
- name: app-source
configMap:
name: library-backend-config
---
apiVersion: v1
kind: Service
metadata:
name: library-backend
spec:
selector:
app: library-backend
ports:
- protocol: TCP
port: 3000
targetPort: 3000
可以使用 React 或 Vue.js 來實現前端,用戶可以通過這個介面來查找和管理書籍。
App.js
import React, { useState, useEffect } from 'react';
function App() {
const [books, setBooks] = useState([]);
const [title, setTitle] = useState('');
const [author, setAuthor] = useState('');
useEffect(() => {
fetch('/api/books')
.then(response => response.json())
.then(data => setBooks(data));
}, []);
const addBook = () => {
fetch('/api/books', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, author })
}).then(() => {
setBooks([...books, { title, author }]);
});
};
return (
<div>
<h1>Library System</h1>
<input placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} />
<input placeholder="Author" value={author} onChange={(e) => setAuthor(e.target.value)} />
<button onClick={addBook}>Add Book</button>
<ul>
{books.map(book => <li key={book.title}>{book.title} by {book.author}</li>)}
</ul>
</div>
);
}
export default App;
apiVersion: apps/v1
kind: Deployment
metadata:
name: library-frontend
spec:
replicas: 1
selector:
matchLabels:
app: library-frontend
template:
metadata:
labels:
app: library-frontend
spec:
containers:
- name: library-frontend
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: app-static
mountPath: /usr/share/nginx/html
volumes:
- name: app-static
configMap:
name: library-frontend-config
---
apiVersion: v1
kind: Service
metadata:
name: library-frontend
spec:
selector:
app: library-frontend
ports:
- protocol: TCP
port: 80
targetPort: 80
如果需要外部訪問前端或 API,可以使用 Kubernetes Ingress 來管理外部流量。
可以使用 kubectl apply -f
命令來依次部署上述的 YAML 檔案:
kubectl apply -f mysql-deployment.yaml
kubectl apply -f backend-deployment.yaml
kubectl apply -f frontend-deployment.yaml
mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1 # 部署一個 MySQL 副本
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7 # 使用 MySQL 5.7 的 Docker 映像
env:
- name: MYSQL_ROOT_PASSWORD
value: rootpassword # MySQL 的 root 使用者密碼
- name: MYSQL_DATABASE
value: library # 預設建立一個名為 library 的資料庫
ports:
- containerPort: 3306 # MySQL 預設的連接埠
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql # 將持久存儲掛載到容器中的 /var/lib/mysql 路徑
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim # 使用 PVC 來請求持久存儲
Deployment
控制器確保應用程式的正確部署與管理。這裡我們只需要一個 MySQL 的副本(replicas: 1
)。volumeMounts
和 volumes
允許 MySQL 使用持久化的存儲,即使容器崩潰或重啟,資料依然保留。persistent-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 1Gi # 定義持久存儲空間為 1 GB
accessModes:
- ReadWriteOnce # 允許單個節點讀寫
hostPath:
path: "/mnt/data" # 在節點上保存資料的路徑
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
spec:
resources:
requests:
storage: 1Gi # 請求 1 GB 的存儲
accessModes:
- ReadWriteOnce # 單個節點讀寫
/mnt/data
。app.js
const express = require('express');
const mysql = require('mysql2');
const app = express();
app.use(express.json()); // 允許應用解析 JSON 請求
// 建立與 MySQL 資料庫的連接
const connection = mysql.createConnection({
host: 'mysql',
user: 'root',
password: 'rootpassword',
database: 'library'
});
// 查詢所有書籍的路由
app.get('/books', (req, res) => {
connection.query('SELECT * FROM books', (err, results) => {
if (err) throw err;
res.json(results); // 回傳所有書籍資料
});
});
// 新增書籍的路由
app.post('/books', (req, res) => {
const { title, author } = req.body;
connection.query('INSERT INTO books (title, author) VALUES (?, ?)', [title, author], (err) => {
if (err) throw err;
res.send('Book added!'); // 回應 "書籍已新增"
});
});
// 後端 API 運行在 3000 埠
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Library API running on port ${PORT}`);
});
app.use(express.json())
設定解析 JSON 的能力,允許 API 接收和處理 JSON 格式的資料。mysql2
建立與 MySQL 的連接,並設定資料庫名稱和帳戶資訊。/books
路由: 這個路由返回資料庫中所有書籍的清單。/books
路由: 允許使用者新增書籍到資料庫中,並回應操作成功。backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: library-backend
spec:
replicas: 1 # 部署一個後端服務副本
selector:
matchLabels:
app: library-backend
template:
metadata:
labels:
app: library-backend
spec:
containers:
- name: library-backend
image: node:14 # 使用 Node.js 14 的 Docker 映像
command: ["npm", "start"] # 啟動應用時執行 npm start
workingDir: /app # 應用的工作目錄
ports:
- containerPort: 3000 # 應用運行在 3000 埠
volumeMounts:
- name: app-source
mountPath: /app # 掛載應用程式的源代碼
volumes:
- name: app-source
configMap:
name: library-backend-config # 從 ConfigMap 獲取應用的源代碼
npm start
命令來啟動應用。App.js
import React, { useState, useEffect } from 'react';
function App() {
const [books, setBooks] = useState([]); // 定義 state 來儲存書籍資料
const [title, setTitle] = useState(''); // 用來輸入書名的 state
const [author, setAuthor] = useState(''); // 用來輸入作者的 state
// 使用 useEffect 在第一次渲染時抓取書籍資料
useEffect(() => {
fetch('/api/books') // 從後端 API 抓取書籍資料
.then(response => response.json())
.then(data => setBooks(data));
}, []);
// 新增書籍
const addBook = () => {
fetch('/api/books', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, author }) // 送出新增的書籍資料
}).then(() => {
setBooks([...books, { title, author }]); // 更新 state,添加新書
});
};
return (
<div>
<h1>Library System</h1>
<input placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} /> {/* 書名輸入 */}
<input placeholder="Author" value={author} onChange={(e) => setAuthor(e.target.value)} /> {/* 作者輸入 */}
<button onClick={addBook}>Add Book</button> {/* 新增書籍按鈕 */}
<ul>
{books.map(book => <li key={book.title}>{book.title} by {book.author}</li>)} {/* 顯示書籍清單 */}
</ul>
</div>
);
}
export default App;
useState
用於定義書籍清單和表單輸入的狀態,useEffect
在頁面載入時從 API 抓取書籍資料。onChange
事件處理,按下按鈕會將新書資料提交給後端 API。frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: library-frontend
spec:
replicas: 1 # 部署一個前端服務副本
selector:
matchLabels:
app: library-frontend
template:
metadata:
labels:
app: library-frontend
spec:
containers:
- name: library-frontend
image: node:14 # 使用 Node.js 來執行前端應用
command: ["npm", "start"] # 使用 npm start 啟動 React 應用
workingDir: /app
ports:
- containerPort: 3000
volumeMounts:
- name: app-source
mountPath: /app
volumes:
- name: app-source
configMap:
name: library-frontend-config
這些文件展示了如何使用 Kubernetes 部署一個完整的應用程式,包括 MySQL 資料庫、Node.js 後端 API 和 React 前端應用。